
#include "FVisDataCenter.h"
#include "UVisDataSubscriber.h"
#include "UVisDataProvider.h"

// Sets default values for this component's properties
UFVisDataCenter::UFVisDataCenter()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;

	// ...
}

void UFVisDataCenter::BuildDataConnections()
{
	// build float data provider/subscriber connections
	floatDataPairs_.Empty();
	for(FFloatVisData& floatVisData : floatDataInfo)
	{
		FVisDataPair<float, FOnFloatProvided> dataPair;
		dataPair.guid = floatVisData.guid;
		dataPair.name = floatVisData.name;
		auto providerActor = floatVisData.providerActor;
		auto provider = providerActor->GetComponentByClass<UVisDataProviderComponent>();
		if (provider)
		{
			dataPair.provider = provider->GetFloatProviderByIndex(floatVisData.poviderDataIndex);
		}

		for (FSubscriberActorInfo& subscriberActor : floatVisData.subscriberActors)
		{
			if (subscriberActor.subscriberActor)
			{
				auto subscriberComp = subscriberActor.subscriberActor->GetComponentByClass<UVisDataSubscriberComponent>();
				if (subscriberComp)
				{
					auto subscriber = subscriberComp->GetFloatSubscriberByIndex(subscriberActor.subscriberDataIndex);
					if (subscriber)
					{
						dataPair.subscribers.Add(&subscriber->GetInternalSubscriber());
					}
				}
			}
		}
		
		dataPair.BindProviderSubscriber();
		floatDataPairs_.Add(dataPair);
	}

	// build int data provider/subscriber connections
	intDataPairs_.Empty();
	for (FIntVisData& intVisData : intData)
	{
		FVisDataPair<int, FOnIntProvided> dataPair;
		dataPair.guid = intVisData.guid;
		dataPair.name = intVisData.name;
		auto providerActor = intVisData.providerActor;
		auto provider = providerActor->GetComponentByClass<UVisDataProviderComponent>();
		if (provider)
		{
			dataPair.provider = provider->GetIntProviderByIndex(intVisData.poviderDataIndex);
		}
		for (FSubscriberActorInfo& subscriberActor : intVisData.subscriberActors)
		{
			if (subscriberActor.subscriberActor)
			{
				auto subscriberComp = subscriberActor.subscriberActor->GetComponentByClass<UVisDataSubscriberComponent>();
				if (subscriberComp)
				{
					auto subscriber = subscriberComp->GetIntSubscriberByIndex(subscriberActor.subscriberDataIndex);
					if (subscriber)
					{
						dataPair.subscribers.Add(&subscriber->GetInternalSubscriber());
					}
				}
			}
		}
		dataPair.BindProviderSubscriber();
		intDataPairs_.Add(dataPair);
	}
}

// Called when the game starts
void UFVisDataCenter::BeginPlay()
{
	Super::BeginPlay();

	BuildDataConnections();
}


// Called every frame
void UFVisDataCenter::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// ...
}

template<typename DataT, typename CallbackEventT>
	requires std::derived_from<CallbackEventT, TMulticastDelegate<void(DataT)>>
inline void FVisDataPair<DataT, CallbackEventT>::BindProviderSubscriber()
{
	if (provider == nullptr || subscribers.Num() == 0)
		return;

	for (auto& sub : subscribers)
	{
		if (sub)
		{
			sub->BindProvider(&provider->GetEvent());
		}
	}
}

//template<typename DataT, typename CallbackEventT>
//	requires std::derived_from<CallbackEventT, TDelegate<void(DataT)>>
//void FVisDataPair<DataT, CallbackEventT>::UnbindProviderSubscriber()
//{
//	if (subscribers.Num() == 0)
//		return;
//	for (auto& sub : subBindProviderCallbackscribers)
//	{
//		if (sub)
//		{
//			provider->GetEvent().UnbindRaw(sub);
//		}
//	}
//}
